use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;

use objc2::rc::Id;
use objc2_app_kit::NSApplication;
use objc2_foundation::MainThreadMarker;

use super::Application;

mod proxy;
pub use proxy::*;
mod rep;
pub use rep::*;

#[derive(Clone, Copy)]
pub struct AppRef<'a>(pub &'a NSApplication);
impl<'a> Deref for AppRef<'a> {
	type Target = NSApplication;
	fn deref(&self) -> &Self::Target {
		self.0
	}
}
impl<'a> types::AppRef for AppRef<'a> {
	type Proxy = AppProxy;
	fn exit(&self) {
		unsafe { self.0.terminate(None) };
	}
	fn proxy(&self) -> Self::Proxy {
		AppProxy(CACHE.with_borrow(|vars| vars.proxy.clone()))
	}
}

pub struct AppHandle(pub Id<NSApplication>);
impl AppHandle {
	pub fn singleton() -> Self {
		let mtm = MainThreadMarker::new().unwrap();
		let app = NSApplication::sharedApplication(mtm);
		AppHandle(app)
	}
}

pub struct AppVars {
	rep: Option<Rc<dyn types::AppRep<Application>>>,
	proxy: Id<AppProxyObj>,
}
thread_local! {
	static CACHE:RefCell<AppVars> = RefCell::new(AppVars {
		rep:None,
		proxy: AppProxyObj::new(),
	});
}
pub(crate) fn init_app(rep: impl types::AppRep<Application>) {
	let rep = Rc::new(rep);
	CACHE.with_borrow_mut(|vars| vars.rep = Some(rep));
}
pub(crate) fn with_app(fun: impl FnOnce(AppRef<'_>)) {
	fun(AppRef(&AppHandle::singleton().0))
}
